2019年鐵人賽
、 JS
由外部引入檔案時要注意加載順序
<head>
區<html>
<head>
...
<script src="./js/test.js">
...
</head>
<body>
...
</body>
</html>
瀏覽器是這麼解讀 document 的,解析一部分 HTML 後暫停,加載和執行 js 後,再繼續解析 HTML
圖片來源:Asynchronous vs Deferred JavaScript
<html>
<head>
...
<script async src="./js/jquery.js"></script>
<script async src="./js/test1.js"></script>
<script async src="js/test2.js"></script>
...
</head>
<body>
...
</body>
</html>
async 屬性告訴瀏覽器可以異步執行(executed asynchronously),
在 HTML 還在解析時加載 js,完全下載後才暫停解析 HTML ,執行 js。
圖片來源:Asynchronous vs Deferred JavaScript
但要注意的是 jquery.js 有可能在 test1.js 和 test2.js 之前或之後加載,順序無法確定,所以如果 test1.js 和 test2.js 裡有使用 jquery 的任何 function 都會出錯
<html>
<head>
...
<script defer src="./js/jquery.js"></script>
<script defer src="./js/test1.js"></script>
<script defer src="js/test2.js"></script>
...
</head>
<body>
...
</body>
</html>
defer 屬性告訴瀏覽器在 HTML 還在解析時加載 js,但是等到 HTML 整個解析完才執行 js。
圖片來源:Asynchronous vs Deferred JavaScript
有defer 屬性的 js 檔會照頁面出現的順序執行
下面範例是透過 js 產生 10 個 <button>
標籤
//HTML body 區
<div id="buttons"></div>
<p></p>
//JS 檔
function showText(i){
let pTag = document.querySelector('p');
pTag.textContent = `按${i+1}`;
}
let divTag = document.querySelector('div');
for(let j = 1; j <= 10; j++){
let btnTag = document.createElement('button');
btnTag.textContent = `按${j}`;
divTag.appendChild(btnTag);
}
let btns = document.querySelectorAll('button');
for(let i = 0; i < btns.length; i++){
btns[i].addEventListener('click',function(){showText(i)});
}
如果放在 <head>
區會造成 js 已經 run 完,所以解析到 HTML body 時只會渲染 <div>
跟 <p>
標籤而已。
解決方法
<html>
<head>
...
</head>
<body>
...
...
<script src="./js/button.js">
</body>
</html>